// Copyright (c) 2024 Go-Frame-Lite
// Go-Frame-Lite is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan
// PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//         http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.

// Package middleware provides HTTP middleware components for the application.
package middleware

import (
	"time"

	"go-frame-lite/pkg/logger"
	"go-frame-lite/pkg/trace"

	"github.com/gin-gonic/gin"
	"go.opentelemetry.io/otel/attribute"
	"go.uber.org/zap"
)

// LoggerGlobal 使用全局日志记录器的中间件（集成OpenTelemetry traceId）
func LoggerGlobal() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		path := c.Request.URL.Path
		query := c.Request.URL.RawQuery

		// 从HTTP请求头中提取追踪上下文
		headers := make(map[string][]string)
		for k, v := range c.Request.Header {
			headers[k] = v
		}

		ctx := trace.ExtractTraceContext(c.Request.Context(), headers)

		// 开始新的Span
		spanName := c.Request.Method + " " + path
		ctx, span := trace.StartSpan(ctx, spanName)
		defer span.End()

		// 设置Span属性
		span.SetAttributes(
			attribute.String("http.method", c.Request.Method),
			attribute.String("http.path", path),
			attribute.String("http.query", query),
			attribute.String("http.client_ip", c.ClientIP()),
			attribute.String("http.user_agent", c.Request.UserAgent()),
		)

		// 更新请求上下文
		c.Request = c.Request.WithContext(ctx)

		// 请求处理前打印日志（包含traceId）
		traceID := trace.GetTraceID(ctx)
		spanID := trace.GetSpanID(ctx)

		logger.Info(ctx, "HTTP请求开始",
			zap.String("trace_id", traceID),
			zap.String("span_id", spanID),
			zap.String("method", c.Request.Method),
			zap.String("path", path),
			zap.String("query", query),
			zap.String("ip", c.ClientIP()),
			zap.String("user-agent", c.Request.UserAgent()),
		)

		// 处理请求
		c.Next()

		// 请求处理后打印日志
		end := time.Now()
		latency := end.Sub(start)

		// 更新Span状态
		span.SetAttributes(
			attribute.Int("http.status_code", c.Writer.Status()),
			attribute.Int64("http.duration_ms", latency.Milliseconds()),
		)

		logger.Info(ctx, "HTTP请求完成",
			zap.String("trace_id", traceID),
			zap.String("span_id", spanID),
			zap.Int("status", c.Writer.Status()),
			zap.String("method", c.Request.Method),
			zap.String("path", path),
			zap.String("query", query),
			zap.String("ip", c.ClientIP()),
			zap.String("user-agent", c.Request.UserAgent()),
			zap.Duration("latency", latency),
		)
	}
}
